package com.lenovo.lcdm.type.util;

import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author
 */
public class StreamUtils {
    private StreamUtils() {
    }

    public static <T> Stream<T> ofStream(Collection<T> col) {
        if (CollectionUtils.isEmpty(col)) {
            return Stream.empty();
        }

        return col.stream();
    }

    /**
     * @return if empty, return Collections#emptyMap, immutable
     */
    public static <K, V, O> Map<K, V> safeGroup(Collection<O> col,
                                                Function<O, K> keyMapper,
                                                Function<O, V> valueMapper) {
        return safeGroup(col, keyMapper, valueMapper, Collections::emptyMap);
    }

    public static <K, V, O> Map<K, V> safeGroup(Collection<O> col,
                                                Function<O, K> keyMapper,
                                                Function<O, V> valueMapper,
                                                Supplier<Map<K, V>> emptyMapSupplier) {
        return safeGroup(col, keyMapper, valueMapper, (v1, v2) -> v2, emptyMapSupplier);
    }

    public static <K, V, O> Map<K, V> safeGroup(Collection<O> col,
                                                Function<O, K> keyMapper,
                                                Function<O, V> valueMapper,
                                                BinaryOperator<V> merger,
                                                Supplier<Map<K, V>> emptyMapSupplier) {
        if (CollectionUtils.isEmpty(col)) {
            return emptyMapSupplier.get();
        }

        return col.stream().collect(Collectors.toMap(keyMapper, valueMapper, merger));
    }

    /**
     * @return if empty, return Collections#emptyMap, immutable
     */
    public static <K, V> Map<K, V> nullToEmpty(Map<K, V> map) {
        return nullToEmpty(map, Collections::emptyMap);
    }

    public static <K, V> Map<K, V> nullToEmpty(Map<K, V> map, Supplier<Map<K, V>> defaultMapSupplier) {
        return CollectionUtils.isEmpty(map) ? defaultMapSupplier.get() : map;
    }

    public static <T> List<T> nullToEmpty(List<T> target) {
        return CollectionUtils.isEmpty(target) ? Collections.emptyList() : target;
    }
}
